package solution.design;

import java.util.*;

/**
 * @author zhangmin
 * @create 2021-10-19 10:03
 *
 * 设计问题：355. 设计推特
 * 设计一个简化版的推特(Twitter)，可以让用户实现发送推文，关注/取消关注其他用户，能够看见关注人（包括自己）的最近 10 条推文。
 */
public class Twitter {

    private static int timestap=0;
    private static class Tweet{
        //每个 Tweet 实例需要记录自己的 tweetId 和发表时间 time，而且作为链表节点，要有一个指向下一个节点的 next 指针。
        private int id;
        private int time;
        private Tweet next;
        private Tweet(int id,int time){
            this.id=id;
            this.time=time;
            this.next=null;
        }
    }
    private static class User{
        //一个用户需要存储的信息有 userId，关注列表，以及该用户发过的推文列表
        private Integer id;
        private HashSet<Integer> followed;
        // 用户发表的推文链表头结点
        private Tweet head;

        public User(Integer id) {
            this.id = id;
            this.followed = new HashSet<>();
            this.head = null;
            follow(id);
        }

        //根据面向对象的设计原则，「关注」「取关」和「发文」应该是 User 的行为
        public void follow(int userId){
            followed.add(userId);
        }
        public void unfollow(int userId){
            if (userId!=this.id)
                followed.remove(userId);
        }

        public void post(int tweetId){
            Tweet t=new Tweet(tweetId,timestap);
            timestap++;
            t.next=head;
            head=t;
        }

    }

    // 我们需要一个映射将 userId 和 User 对象对应起来
    private HashMap<Integer, User> userMap = new HashMap<>();

    public Twitter() {

    }

    // 根据给定的 tweetId 和 userId 创建一条新推文。每次调用次函数都会使用一个不同的 tweetId
    public void postTweet(int userId, int tweetId) {
        if (!userMap.containsKey(userId))
            userMap.put(userId,new User(userId));
        User user=userMap.get(userId);
        user.post(tweetId);
    }

    //检索当前用户新闻推送中最近  10 条推文的 ID 。新闻推送中的每一项都必须是由用户关注的人或者是用户自己发布的推文。推文必须 按照时间顺序由最近到最远排序 。--优先队列
    public List<Integer> getNewsFeed(int userId) {
        List<Integer> res=new ArrayList<>();
        if (!userMap.containsKey(userId)) return res;
        //获得关注用户列表
        HashSet<Integer> followedUsers=userMap.get(userId).followed;
        //优先队列：按时间从大到小排序
        PriorityQueue<Tweet> queue=new PriorityQueue<>(followedUsers.size(), (o1, o2) -> o2.time-o1.time);
        // 先将所有链表头节点插入优先级队列
        for (int id:followedUsers) {
            Tweet headTWT = userMap.get(id).head;
            if (headTWT==null) continue;
            queue.add(headTWT);
        }
        while (!queue.isEmpty()){
            if (res.size()==10) break;
            Tweet tweet = queue.poll();
            res.add(tweet.id);
            if (tweet.next!=null)
                queue.add(tweet.next);
        }
        return res;
    }

    // ID 为 followerId 的用户开始关注 ID 为 followeeId 的用户。
    public void follow(int followerId, int followeeId) {
        if (!userMap.containsKey(followerId)){
            userMap.put(followerId,new User(followerId));
        }
        if (!userMap.containsKey(followeeId))
            userMap.put(followeeId,new User(followeeId));
        User user=userMap.get(followerId);
        user.follow(followeeId);
    }

    //ID 为 followerId 的用户不再关注 ID 为 followeeId 的用户。
    public void unfollow(int followerId, int followeeId) {
        if (userMap.containsKey(followerId)){
            User user=userMap.get(followerId);
            user.unfollow(followeeId);
        }
    }

}
